package com.neu;

import com.neu.discovery.Registry;
import com.neu.discovery.RegistryConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 杜佳辉
 * @version 1.0
 * @date 2024-12-05-19:57
 */
@Slf4j
public class rpcBootstrap {

    //rpcBootstrap是个单例，我们希望每个应用程序都只有一个rpcBootstrap
    private static final rpcBootstrap rpcBootstrap = new rpcBootstrap();
    // 维护已经发布且暴露的服务列表 key-> interface的全限定名  value -> ServiceConfig
    public final static Map<String, ServiceConfig<?>> SERVERS_LIST = new ConcurrentHashMap<>(16);
    // 连接的缓存,如果使用InetSocketAddress这样的类做key，一定要看他有没有重写equals方法和toString方法
    public final static Map<InetSocketAddress, Channel> CHANNEL_CACHE = new ConcurrentHashMap<>(16);
    public final static TreeMap<Long, Channel> ANSWER_TIME_CHANNEL_CACHE = new TreeMap<>();
    private Registry registry;
    private RegistryConfig registryConfig;
    public static rpcBootstrap getInstance() {
        return rpcBootstrap;
    }

    public rpcBootstrap() {
    }

    /**
     * 用来配置应用名
     * @param s
     * @return  this当前对象
     */
    public rpcBootstrap application(String s) {
        return this;
    }

    /**
     * 用来配置注册中心
     * @param registryConfig
     * @return this当前对象
     */
    public rpcBootstrap registry(RegistryConfig registryConfig) {
        registry = registryConfig.getRegistry();
        return this;
    }

    /**
     * 序列化器
     * @param serializeType
     * @return
     */
    public rpcBootstrap serialize(String serializeType) {
        if (log.isDebugEnabled()) {
            log.debug("我们配置了使用的序列化的方式为【{}】.", serializeType);
        }
        return this;
    }

    /**
     * 扫描指定包下的所有类
     * @param packageName
     * @return
     */
    public rpcBootstrap scan(String packageName) {
        return this;
    }

    /**
      ---------------------------服务提供方的相关api---------------------------------
     */

    /**
     * 发布服务，将服务注册到注册中心
     * @param service 发布服务
     * @return this当前对象
     */
    public rpcBootstrap publish(ServiceConfig<?> service) {

        if (log.isDebugEnabled()) {
            log.debug("我们配置了发布服务【{}】.", service.getInterfaceProvider().getName());
        }
        registry.register(service);
        // 1、当服务调用方，通过接口、方法名、具体的方法参数列表发起调用，提供怎么知道使用哪一个实现
        // (1) new 一个  （2）spring beanFactory.getBean(Class)  (3) 自己维护映射关系
        SERVERS_LIST.put(service.getInterface().getName(), service);
        return this;
    }

    /**
     * 启动netty服务
     */
    public void start() {
        // 注册关闭应用程序的钩子函数
//        Runtime.getRuntime().addShutdownHook(new rpcShutdownHook());

        // 1、创建eventLoop，老板只负责处理请求，之后会将请求分发至worker
        EventLoopGroup boss = new NioEventLoopGroup(2);
        EventLoopGroup worker = new NioEventLoopGroup(10);
        try {

            // 2、需要一个服务器引导程序
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            // 3、配置服务器
            serverBootstrap = serverBootstrap.group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // 是核心，我们需要添加很多入站和出站的handler
                            socketChannel.pipeline().addLast(new LoggingHandler())
//                                    .addLast(new rpcRequestDecoder())
                                    // 根据请求进行方法调用
//                                    .addLast(new MethodCallHandler())
//                                    .addLast(new rpcResponseEncoder())
                            ;
                        }
                    });

            // 4、绑定端口
            ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();

            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                boss.shutdownGracefully().sync();
                worker.shutdownGracefully().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * ---------------------------服务调用方的相关api---------------------------------
     */
    public rpcBootstrap reference(ReferenceConfig<?> reference) {
        reference.setRegistry(registry);
        return this;
    }
}
